//
//  CAShapeLayerViewController.m
//  CoreAnimation
//
//  Created by 张国文 on 16/10/13.
//  Copyright © 2016年 hangzhouyijiyin. All rights reserved.
//

#import "CAShapeLayerViewController.h"

@interface CAShapeLayerViewController ()

@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic, strong) UILabel *showFillRuleType; // 显示fillRule的类型

@end

@implementation CAShapeLayerViewController

/**
 *  前言：CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。你指定诸如颜色和线宽等属性，用CGPath来定义想要绘制的图形，最后CAShapeLayer就自动渲染出来了。当然，你也可以用Core Graphics直接向原始的CALyer的内容中绘制一个路径，相比直下，使用⚠️CAShapeLayer有以下一些优点：
 
 渲染快速。CAShapeLayer使用了硬件加速，绘制同一图形会比用Core Graphics快很多。
 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形，所以无论有多大，都不会占用太多的内存。
 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉（如我们在第二章所见）。
 不会出现像素化。当你给CAShapeLayer做3D变换时，它不像一个有寄宿图的普通图层一样变得像素化。
  ⚠️：也就是说用CALayer中特定图层，比让UIView执行drawRect渲染的更快，因为CALayer的特定图层绘制内容有硬件加速。
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    // http://blog.csdn.net/iunion/article/details/26221213 这个链接上面对CAShapeLayer有非常详细的介绍，本节的例子在这个链接上都有
    
    self.backgroundView = [[UIView alloc] initWithFrame:self.view.frame];
    self.backgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.5];
    [self.view addSubview:_backgroundView];
    
    // 创建一个火柴人
//    [self createMatchPeople];
    // fillRule(填充规则)
//    [self createCircle];
    // miterLimit 最大衔接长度
//    [self testMiterLimit];
    // 创建一个圆角矩形
    [self createRoundRect];
}

// 创建一个火柴人
- (void)createMatchPeople
{
  
    
    UIBezierPath *path = [[UIBezierPath alloc] init];
    [path moveToPoint:CGPointMake(175, 100)];
    [path addArcWithCenter:CGPointMake(150, 100) radius:25 startAngle:0 endAngle:2*M_PI clockwise:YES];
    [path moveToPoint:CGPointMake(150, 125)];
    [path addLineToPoint:CGPointMake(150, 175)];
    [path addLineToPoint:CGPointMake(125, 225)];
    [path moveToPoint:CGPointMake(150, 175)];
    [path addLineToPoint:CGPointMake(175, 225)];
    [path moveToPoint:CGPointMake(100, 150)];
    [path addLineToPoint:CGPointMake(200, 150)];
    
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.strokeColor = [UIColor redColor].CGColor; // 边框颜色
    shapeLayer.fillColor = [UIColor clearColor].CGColor; // 填充的颜色
    shapeLayer.lineWidth = 5; // 线条宽度
    shapeLayer.lineJoin = kCALineJoinRound; // 线条链接端的形状，两条线的交合处
    shapeLayer.lineCap = kCALineCapRound; // 线条端点的形状，一条线的起始处
#warning - lineDashPattern和lineDashPhase的说明，http://blog.csdn.net/iunion/article/details/26221213   这个链接有更加详细的解释
//    // 这里要着重说明一下lineDashPattern这个属性，这个属性是一个数组，其实就是画虚线用的，这个属性必须在path赋值之前调用，否则没用。说明一下：奇数为表示要绘制的长度，偶数为表示要跳过的长度。如果只设置一位的话，默认是绘制和跳过的长度相等。 需要注意的是：这个属性要明显体现出效果的话需要将lineCap注释掉
////    shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:5], [NSNumber numberWithInt:5], [NSNumber numberWithInt:3], nil];
////    shapeLayer.lineDashPhase = 3; // 这个表示在使用lineDashPattern的时候第一个位点要减去的长度，这个属性必须要和lineDashPattern配合使用才有效果
//    shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:5], nil]; // 绘制和跳过的长度相等
    shapeLayer.path = path.CGPath;
    [self.backgroundView.layer addSublayer:shapeLayer];
    
   
    // 在这里说明一下：strokeEnd默认值为1，即视图还没有画的剩下的部分，取值为0~1，strokeStart默认值为0，视图已经画的部分，取值为0~1
    
    // 当然我们也可以为shapeLayer添加动画
#pragma mark - 动画一
    // 下面的动画相当于是让视图从起始点开始画，从头到尾，是不是很炫
//    CABasicAnimation *baseAnimatoin = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
//    baseAnimatoin.fromValue = [NSNumber numberWithFloat:0];
//    baseAnimatoin.toValue = [NSNumber numberWithFloat:1];
//    baseAnimatoin.duration = 3;
//    [shapeLayer addAnimation:baseAnimatoin forKey:@"changeStrokeEnd"];
   
#pragma mark - 动画二
    // 为了区分strokeEnd，我们用strokeStart来模拟一下，这个动画相当于让动画的起止点位于视图的末尾，从末尾向头画
//    CABasicAnimation *baseAnimatoin = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; // keyPath可以使CALayer的所有属性
//    baseAnimatoin.fromValue = [NSNumber numberWithFloat:1];
//    baseAnimatoin.toValue = [NSNumber numberWithFloat:0];
//    baseAnimatoin.duration = 3;
//    [shapeLayer addAnimation:baseAnimatoin forKey:@"changeStrokeStart"]; // 这个key只是为我们的动画起了一个key，具体用法可以根据这个key进行动画的删除等操作
    
#pragma mark - 动画三
//    // 当然我们也可以将strokeStart和strokeEnd一起使用，比如我们让动画从中间开始向两头画
//        CABasicAnimation *baseAnimatoin1 = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; // keyPath可以使CALayer的所有属性
//        baseAnimatoin1.fromValue = [NSNumber numberWithFloat:0.5];
//        baseAnimatoin1.toValue = [NSNumber numberWithFloat:0];
//        baseAnimatoin1.duration = 3;
//        [shapeLayer addAnimation:baseAnimatoin1 forKey:@"changeStrokeStart"];
//    
//        CABasicAnimation *baseAnimatoin2 = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; // keyPath可以使CALayer的所有属性
//        baseAnimatoin2.fromValue = [NSNumber numberWithFloat:0.5];
//        baseAnimatoin2.toValue = [NSNumber numberWithFloat:1];
//        baseAnimatoin2.duration = 3;
//        [shapeLayer addAnimation:baseAnimatoin2 forKey:@"changeStrokeEnd"];
    
    // 有兴趣的同志可以自己改变一下strokeStart和strokeEnd，来达到更加炫酷的效果
}

#pragma mark - fillRule(填充规则) non-zero' and`even-odd'. Defaults to `non-zero'. 这个方法的规则需要用心去感受，建议自己在纸上画几个同心圆，设置不同的方向，然后根据规则自己算算重合的点数，这样才能够彻底理解，只看结论是没有意义的。
/**
 *  结论：使用non-zero：nonzero字面意思是“非零”。按该规则，要判断一个点是否在图形内，从该点作任意方向的一条射线，然后检测射线与图形路径的交点情况。从0开始计数，路径从左向右穿过射线则计数加1，从右向左穿过射线则计数减1。得出计数结果后，如果结果是0，则认为点在图形外部，否则认为在内部。
                 使用even-odd：奇数填充，偶数不填充， evenodd字面意思是“奇偶”。按该规则，要判断一个点是否在图形内，从该点作任意方向的一条射线，然后检测射线与图形路径的交点的数量。如果结果是奇数则认为点在内部，是偶数则认为点在外部。
 */
- (void)createCircle
{
    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    button1.frame = CGRectMake(0, 450, 375 / 2, 30);
    [button1 setTitle:@"同向使用non-zero" forState:UIControlStateNormal];
    [button1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button1.tag = 200;
    [self.view addSubview:button1];
    
    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
    button2.frame = CGRectMake(0, 480, 375 / 2, 30);
    [button2 setTitle:@"不同向使用non-zero" forState:UIControlStateNormal];
    [button2 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button2 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button2.tag = 201;
    [self.view addSubview:button2];
    
    UIButton *button3 = [UIButton buttonWithType:UIButtonTypeCustom];
    button3.frame = CGRectMake(375 / 2, 450, 375 / 2, 30);
    [button3 setTitle:@"同向使用even-odd" forState:UIControlStateNormal];
    [button3 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button3 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button3.tag = 202;
    [self.view addSubview:button3];
    
    UIButton *button4 = [UIButton buttonWithType:UIButtonTypeCustom];
    button4.frame = CGRectMake(375 / 2, 480, 375 / 2, 30);
    [button4 setTitle:@"不同向使用even-odd" forState:UIControlStateNormal];
    [button4 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button4 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button4.tag =  203;
    [self.view addSubview:button4];
    
    UIButton *button5 = [UIButton buttonWithType:UIButtonTypeCustom];
    button5.frame = CGRectMake(0, 510, 375, 30);
    [button5 setTitle:@"三圆同向使用even-odd" forState:UIControlStateNormal];
    [button5 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button5 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button5.tag =  204;
    [self.view addSubview:button5];
    
    UIButton *button6 = [UIButton buttonWithType:UIButtonTypeCustom];
    button6.frame = CGRectMake(0, 540, 375, 30);
    [button6 setTitle:@"三圆不同向使用even-odd" forState:UIControlStateNormal];
    [button6 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button6 addTarget:self action:@selector(changeRonate:) forControlEvents:UIControlEventTouchUpInside];
    button6.tag =  205;
    [self.view addSubview:button6];
    
    self.showFillRuleType = [[UILabel alloc] initWithFrame:CGRectMake(0, 380, self.view.frame.size.width, 30)];
    self.showFillRuleType.backgroundColor = [UIColor whiteColor];
    self.showFillRuleType.textColor = [UIColor cyanColor];
    self.showFillRuleType.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:_showFillRuleType];
   
}

- (void)changeRonate:(UIButton *)button
{
    for (int i = 0; i < self.backgroundView.layer.sublayers.count; i++) {
        if ([self.backgroundView.layer.sublayers[i] isKindOfClass:[CAShapeLayer class]]) {
            [self.backgroundView.layer.sublayers[i] removeFromSuperlayer];
        }
    }
    switch (button.tag) {
        case 200:
        {
            self.showFillRuleType.text = @"二圆fillRule:同向使用non-zero";
            // 两个圆 同向使用non-zero
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:YES];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
            shapeLayer.fillRule = kCAFillRuleNonZero;
            //shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;
            
            //add it to our view
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
            case 201:
        {
            self.showFillRuleType.text = @"二圆fillRule:不同向使用non-zero";
            // 两个圆 不同向使用non-zero
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:-2*M_PI clockwise:NO];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
            shapeLayer.fillRule = kCAFillRuleNonZero;
            //shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;
            
            //add it to our view
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
            case 202:
        {
            self.showFillRuleType.text = @"二圆fillRule:同向使用even-odd";
            // 两个圆 同向使用even-odd
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:YES];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
           // shapeLayer.fillRule = kCAFillRuleNonZero;
            shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;
            
            //add it to our view
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
            case 203:
        {
            self.showFillRuleType.text = @"二圆fillRule:不同向使用even-odd";
            // 两个圆 不同向使用even-odd
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:-2*M_PI clockwise:NO];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
          //  shapeLayer.fillRule = kCAFillRuleNonZero;
            shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;
            
            //add it to our view
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
            case 204:
        {
            self.showFillRuleType.text = @"三圆 fillRule:同向使用even-odd";
            // 三圆同向使用even-odd
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(300, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:150 startAngle:0 endAngle:2*M_PI clockwise:YES];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
            //shapeLayer.fillRule = kCAFillRuleNonZero;
            shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;  
            
            //add it to our view  
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
            case 205:
        {
            self.showFillRuleType.text = @"三圆 fillRule:不同向使用even-odd";
            // 三圆不同向使用even-odd
            //create path
            UIBezierPath *path = [[UIBezierPath alloc] init];
            [path moveToPoint:CGPointMake(200, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
            [path moveToPoint:CGPointMake(250, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:-2*M_PI clockwise:NO];
            [path moveToPoint:CGPointMake(300, 150)];
            [path addArcWithCenter:CGPointMake(150, 150) radius:150 startAngle:0 endAngle:2*M_PI clockwise:YES];
            
            //create shape layer
            CAShapeLayer *shapeLayer = [CAShapeLayer layer];
            shapeLayer.strokeColor = [UIColor redColor].CGColor;
            shapeLayer.fillColor = [UIColor blueColor].CGColor;
            //shapeLayer.fillRule = kCAFillRuleNonZero;
            shapeLayer.fillRule = kCAFillRuleEvenOdd;
            
            shapeLayer.lineWidth = 5;
            shapeLayer.lineJoin = kCALineJoinBevel;
            shapeLayer.lineCap = kCALineCapRound;
            shapeLayer.path = path.CGPath;
            
            //add it to our view
            [self.backgroundView.layer addSublayer:shapeLayer];
            break;
        }
        default:
            break;
    }
}

#pragma mark - miterLimit 最大衔接长度
- (void)testMiterLimit
{
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(50, 50)];
    [bezierPath addLineToPoint:CGPointMake(200, 70)];
    [bezierPath addLineToPoint:CGPointMake(50, 90)];
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.lineWidth = 10.0f;
    shapeLayer.lineJoin = kCALineJoinMiter;
    shapeLayer.lineCap = kCALineCapRound;
    shapeLayer.strokeColor = [UIColor redColor].CGColor;
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeLayer.path = bezierPath.CGPath;
    shapeLayer.miterLimit = 5; // 这个属性就是两条线交合处的最大长度，如果超过这个长度以后就会lineJoin = kCALineJoinBevel来显示，这个属性只有在lineJoin = kCALineJoinMiter才会有用
    [self.backgroundView.layer addSublayer:shapeLayer];
}

// 创建一个圆角矩形
- (void)createRoundRect
{
    CGRect roundRect = CGRectMake(50, 50, 200, 200);
    CGSize cornerRadii = CGSizeMake(60, 60);
    UIRectCorner cornes = UIRectCornerTopLeft | UIRectCornerTopRight;
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:roundRect byRoundingCorners:cornes cornerRadii:cornerRadii];
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = path.CGPath;
    shapeLayer.fillColor = [UIColor redColor].CGColor;
    shapeLayer.strokeColor = [UIColor clearColor].CGColor;
    [self.backgroundView.layer addSublayer:shapeLayer];
}

@end
